<!DOCTYPE html>
<html lang="en">





<head>
  <meta charset="UTF-8">
  <link rel="apple-touch-icon" sizes="76x76" href="/zezhang/img/favicon.webp">
  <link rel="icon" type="image/png" href="/zezhang/img/favicon.webp">
  <meta name="viewport"
        content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, shrink-to-fit=no">
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  
  <meta name="theme-color" content="#2f4154">
  <meta name="description" content="">
  <meta name="author" content="ZeZhang">
  <meta name="keywords" content="">
  <title>作用域和封包 - 你那里天气还好吗?</title>

  <link  rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/4.4.1/css/bootstrap.min.css" />


  <link  rel="stylesheet" href="https://cdn.staticfile.org/github-markdown-css/4.0.0/github-markdown.min.css" />
  <link  rel="stylesheet" href="/zezhang/lib/hint/hint.min.css" />

  
    <link  rel="stylesheet" href="https://cdn.staticfile.org/highlight.js/10.0.0/styles/github-gist.min.css" />
  

  


<!-- 主题依赖的图标库，不要自行修改 -->

<link rel="stylesheet" href="//at.alicdn.com/t/font_1749284_yg9cfy8wd6.css">



<link rel="stylesheet" href="//at.alicdn.com/t/font_1736178_pjno9b9zyxs.css">


<link  rel="stylesheet" href="/zezhang/css/main.css" />

<!-- 自定义样式保持在最底部 -->


  <script  src="/zezhang/js/utils.js" ></script>
<meta name="generator" content="Hexo 4.2.0"></head>


<body>
  <header style="height: 70vh;">
    <nav id="navbar" class="navbar fixed-top  navbar-expand-lg navbar-dark scrolling-navbar">
  <div class="container">
    <a class="navbar-brand"
       href="/zezhang/">&nbsp;<strong>你那里天气还好吗?</strong>&nbsp;</a>

    <button id="navbar-toggler-btn" class="navbar-toggler" type="button" data-toggle="collapse"
            data-target="#navbarSupportedContent"
            aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <div class="animated-icon"><span></span><span></span><span></span></div>
    </button>

    <!-- Collapsible content -->
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav ml-auto text-center">
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/zezhang/">
                <i class="iconfont icon-home-fill"></i>
                Home
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/zezhang/archives/">
                <i class="iconfont icon-archive-fill"></i>
                Archives
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/zezhang/tags/">
                <i class="iconfont icon-tags-fill"></i>
                Tags
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/zezhang/about/">
                <i class="iconfont icon-user-fill"></i>
                About
              </a>
            </li>
          
        
        
          <li class="nav-item" id="search-btn">
            <a class="nav-link" data-toggle="modal" data-target="#modalSearch">&nbsp;&nbsp;<i
                class="iconfont icon-search"></i>&nbsp;&nbsp;</a>
          </li>
        
      </ul>
    </div>
  </div>
</nav>

    <div class="view intro-2" id="background" parallax=true
         style="background: url('/zezhang/img/banner8.webp') no-repeat center center;
           background-size: cover;">
      <div class="full-bg-img">
        <div class="mask flex-center" style="background-color: rgba(0, 0, 0, 0.3)">
          <div class="container text-center white-text fadeInUp">
            <span class="h2" id="subtitle">
              
            </span>

            
              
  <div class="mt-3 post-meta">
    <i class="iconfont icon-date-fill" aria-hidden="true"></i>
    <time datetime="2020-02-01 00:00">
      February 1, 2020 am
    </time>
  </div>


<div class="mt-1">
  
    
    <span class="post-meta mr-2">
      <i class="iconfont icon-chart"></i>
      4.8k 字
    </span>
  

  
    
    <span class="post-meta mr-2">
      <i class="iconfont icon-clock-fill"></i>
      
      
      55
       分钟
    </span>
  

  
  
</div>

            
          </div>

          
        </div>
      </div>
    </div>
  </header>

  <main>
    
      

<div class="container-fluid">
  <div class="row">
    <div class="d-none d-lg-block col-lg-2"></div>
    <div class="col-lg-8 nopadding-md">
      <div class="container nopadding-md" id="board-ctn">
        <div class="py-5" id="board">
          <div class="post-content mx-auto" id="post">
            
            <article class="markdown-body">
              <h2 id="执行上下文"><a href="#执行上下文" class="headerlink" title="执行上下文"></a>执行上下文</h2><p>执行上下文主要有两种情况：</p>
<ul>
<li><p>全局代码： 一段<code>&lt;script&gt;</code>标签里，有一个全局的执行上下文。所做的事情是：变量定义、函数声明</p>
</li>
<li><p>函数代码：每个函数里有一个上下文。所做的事情是：变量定义、函数声明、this、arguments</p>
</li>
</ul>
<p>PS：注意“函数声明”和“函数表达式”的区别。</p>
<h3 id="全局执行上下文"><a href="#全局执行上下文" class="headerlink" title="全局执行上下文"></a>全局执行上下文</h3><p>在执行全局代码前将window确定为全局执行上下文。</p>
<p>（1）对全局数据进行预处理：（并没有赋值）</p>
<ul>
<li><p>var定义的全局变量==&gt;undefined, 添加为window的属性</p>
</li>
<li><p>function声明的全局函数==&gt;赋值(fun), 添加为window的方法</p>
</li>
<li><p>this==&gt;赋值(window)</p>
</li>
</ul>
<p>（2）开始执行全局代码</p>
<p><img src="http://img.smyhvae.com/20180311_1100.png" srcset="/zezhang/img/loading.gif" alt=""></p>
<h3 id="函数执行上下文"><a href="#函数执行上下文" class="headerlink" title="函数执行上下文"></a>函数执行上下文</h3><p>在调用函数, 准备执行函数体之前, 创建对应的函数执行上下文对象(虚拟的, 存在于栈中)。</p>
<p>（1）对局部数据进行预处理：</p>
<ul>
<li><p>形参变量==&gt;赋值(实参)==&gt;添加为执行上下文的属性</p>
</li>
<li><p>arguments==&gt;赋值(实参列表), 添加为执行上下文的属性</p>
</li>
<li><p>var定义的局部变量==&gt;undefined, 添加为执行上下文的属性</p>
</li>
<li><p>function声明的函数 ==&gt;赋值(fun), 添加为执行上下文的方法</p>
</li>
<li><p>this==&gt;赋值(调用函数的对象)</p>
</li>
</ul>
<p>（2）开始执行函数体代码</p>
<h3 id="执行上下文栈"><a href="#执行上下文栈" class="headerlink" title="执行上下文栈"></a>执行上下文栈</h3><ul>
<li><p>1.在全局代码执行前, JS引擎就会创建一个栈来存储管理所有的执行上下文对象</p>
</li>
<li><p>2.在全局执行上下文(window)确定后, 将其添加到栈中(压栈)</p>
</li>
<li><p>3.在函数执行上下文创建后, 将其添加到栈中(压栈)</p>
</li>
<li><p>4.在当前函数执行完后,将栈顶的对象移除(出栈)</p>
</li>
<li><p>5.当所有的代码执行完后, 栈中只剩下window</p>
</li>
</ul>
<h2 id="this"><a href="#this" class="headerlink" title="this"></a>this</h2><p>this指的是，<strong>调用函数的那个对象</strong>。this永远指向函数运行时所在的对象。</p>
<p>解析器在调用函数每次都会向函数内部传递进一个隐含的参数，这个隐含的参数就是this。</p>
<p>根据函数的调用方式的不同，this会指向不同的对象：【重要】</p>
<ul>
<li><p>1.以函数的形式调用时，this永远都是window。比如<code>fun();</code>相当于<code>window.fun();</code></p>
</li>
<li><p>2.以方法的形式调用时，this是调用方法的那个对象</p>
</li>
<li><p>3.以构造函数的形式调用时，this是新创建的那个对象</p>
</li>
<li><p>4.使用call和apply调用时，this是指定的那个对象</p>
</li>
</ul>
<p>需要特别提醒的是：this的指向在函数定义时无法确认，只有函数执行时才能确定。</p>
<p><img src="http://img.smyhvae.com/20180311_1117.png" srcset="/zezhang/img/loading.gif" alt=""></p>
<p>this的几种场景：</p>
<ul>
<li>1、作为构造函数执行</li>
</ul>
<p>例如：</p>
<pre><code class="hljs javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Foo</span>(<span class="hljs-params">name</span>) </span>&#123;
    <span class="hljs-comment">//this = &#123;&#125;;</span>
    <span class="hljs-keyword">this</span>.name = name;
    <span class="hljs-comment">//return this;</span>
&#125;

<span class="hljs-keyword">var</span> foo = <span class="hljs-keyword">new</span> Foo();</code></pre>

<ul>
<li>2、作为对象的属性执行</li>
</ul>
<pre><code class="hljs javascript"><span class="hljs-keyword">var</span> obj = &#123;
    <span class="hljs-attr">name</span>: <span class="hljs-string">'A'</span>,
    <span class="hljs-attr">printName</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>&#123;
        <span class="hljs-built_in">console</span>.log(<span class="hljs-keyword">this</span>.name);
    &#125;
&#125;

obj.printName();</code></pre>


<ul>
<li>3、作为普通函数执行</li>
</ul>
<pre><code class="hljs javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fn</span>(<span class="hljs-params"></span>) </span>&#123;
    <span class="hljs-built_in">console</span>.log(<span class="hljs-keyword">this</span>); <span class="hljs-comment">//this === window</span>
&#125;

fn();</code></pre>



<ul>
<li>4、call apply bind</li>
</ul>
<h2 id="作用域"><a href="#作用域" class="headerlink" title="作用域"></a>作用域</h2><p>作用域指一个变量的<strong>作用范围</strong>。它是静态的(相对于上下文对象), 在编写代码时就确定了。</p>
<p>作用：隔离变量，不同作用域下同名变量不会有冲突。</p>
<p>作用域的分类：</p>
<ul>
<li><p>全局作用域</p>
</li>
<li><p>函数作用域</p>
</li>
<li><p>没有块作用域(ES6有了)</p>
</li>
</ul>
<pre><code class="hljs javascript"><span class="hljs-keyword">if</span> (<span class="hljs-literal">true</span>) &#123;
    <span class="hljs-keyword">var</span> name = <span class="hljs-string">'smyhvae'</span>;
&#125;
<span class="hljs-built_in">console</span>.log(name);</code></pre>


<p>上方代码中，并不会报错，因为：虽然 name 是在块里面定义的，但是 name 是全局变量。</p>
<h3 id="全局作用域"><a href="#全局作用域" class="headerlink" title="全局作用域"></a>全局作用域</h3><p>直接编写在script标签中的JS代码，都在全局作用域。</p>
<p>在全局作用域中：</p>
<ul>
<li>在全局作用域中有一个全局对象window，它代表的是一个浏览器的窗口，它由浏览器创建我们可以直接使用。</li>
</ul>
<ul>
<li><p>创建的变量都会作为window对象的属性保存。</p>
</li>
<li><p>创建的函数都会作为window对象的方法保存。</p>
</li>
</ul>
<p>全局作用域中的变量都是全局变量，在页面的任意的部分都可以访问到。</p>
<p><strong>变量的声明提前：</strong>（变量提升）</p>
<p>使用var关键字声明的变量（ 比如 <code>var a = 1</code>），<strong>会在所有的代码执行之前被声明</strong>（但是不会赋值），但是如果声明变量时不是用var关键字（比如直接写<code>a = 1</code>），则变量不会被声明提前。</p>
<p>举例1：</p>
<pre><code class="hljs javascript"><span class="hljs-built_in">console</span>.log(a);
<span class="hljs-keyword">var</span> a = <span class="hljs-number">123</span>;</code></pre>


<p>打印结果：undefined</p>
<p>举例2：</p>
<pre><code class="hljs javascript"><span class="hljs-built_in">console</span>.log(a);
a = <span class="hljs-number">123</span>;   <span class="hljs-comment">//此时a相当于window.a</span></code></pre>

<p>程序会报错：</p>
<p><img src="http://img.smyhvae.com/20180314_2136.png" srcset="/zezhang/img/loading.gif" alt=""></p>
<p><strong>函数的声明提前：</strong></p>
<ul>
<li>使用<code>函数声明</code>的形式创建的函数<code>function foo(){}</code>，<strong>会被声明提前</strong>。</li>
</ul>
<p>也就是说，它会在所有的代码执行之前就被创建，所以我们可以在函数声明之前，调用函数。</p>
<ul>
<li>使用<code>函数表达式</code>创建的函数<code>var foo = function(){}</code>，<strong>不会被声明提前</strong>，所以不能在声明前调用。</li>
</ul>
<p>很好理解，因为此时foo被声明了，且为undefined，并没有给其赋值<code>function(){}</code>。</p>
<p>所以说，下面的例子，会报错：</p>
<p><img src="http://img.smyhvae.com/20180314_2145.png" srcset="/zezhang/img/loading.gif" alt=""></p>
<h3 id="函数作用域"><a href="#函数作用域" class="headerlink" title="函数作用域"></a>函数作用域</h3><p><strong>调用函数时创建函数作用域，函数执行完毕以后，函数作用域销毁。</strong></p>
<p>每调用一次函数就会创建一个新的函数作用域，他们之间是互相独立的。</p>
<p>在函数作用域中可以访问到全局作用域的变量，在全局作用域中无法访问到函数作用域的变量。</p>
<p>在函数中要访问全局变量可以使用window对象。（比如说，全局作用域和函数作用域都定义了变量a，如果想访问全局变量，可以使用<code>window.a</code>）</p>
<p><strong>提醒1：</strong></p>
<p>在函数作用域也有声明提前的特性：</p>
<ul>
<li><p>使用var关键字声明的变量，是在函数作用域内有效，而且会在函数中所有的代码执行之前被声明</p>
</li>
<li><p>函数声明也会在函数中所有的代码执行之前执行</p>
</li>
</ul>
<p>因此，在函数中，没有var声明的变量都会成为<strong>全局变量</strong>，而且并不会提前声明。</p>
<p>举例1：</p>
<pre><code class="hljs javascript"><span class="hljs-keyword">var</span> a = <span class="hljs-number">1</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">foo</span>(<span class="hljs-params"></span>) </span>&#123;
    <span class="hljs-built_in">console</span>.log(a);
    a = <span class="hljs-number">2</span>;     <span class="hljs-comment">// 此处的a相当于window.a</span>
&#125;

foo();
<span class="hljs-built_in">console</span>.log(a);   <span class="hljs-comment">//打印结果是2</span></code></pre>

<p>上方代码中，foo()的打印结果是<code>1</code>。如果去掉第一行代码，打印结果是<code>Uncaught ReferenceError: a is not defined</code></p>
<p><strong>提醒2：</strong>定义形参就相当于在函数作用域中声明了变量。</p>
<pre><code class="hljs delphi">
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fun6</span><span class="hljs-params">(e)</span> <span class="hljs-comment">&#123;
    console.log(e);
&#125;</span>

<span class="hljs-title">fun6</span><span class="hljs-params">()</span>;</span>  <span class="hljs-comment">//打印结果为 undefined</span>
fun6(<span class="hljs-number">123</span>);<span class="hljs-comment">//打印结果为123</span></code></pre>



<h3 id="作用域与执行上下文的区别"><a href="#作用域与执行上下文的区别" class="headerlink" title="作用域与执行上下文的区别"></a>作用域与执行上下文的区别</h3><p>区别1：</p>
<ul>
<li><p>全局作用域之外，每个函数都会创建自己的作用域，作用域在函数定义时就已经确定了。而不是在函数调用时</p>
</li>
<li><p>全局执行上下文环境是在全局作用域确定之后, js代码马上执行之前创建</p>
</li>
<li><p>函数执行上下文是在调用函数时, 函数体代码执行之前创建</p>
</li>
</ul>
<p>区别2：</p>
<ul>
<li><p>作用域是静态的, 只要函数定义好了就一直存在, 且不会再变化</p>
</li>
<li><p>执行上下文是动态的, 调用函数时创建, 函数调用结束时就会自动释放</p>
</li>
</ul>
<p>联系：</p>
<ul>
<li><p>执行上下文(对象)是从属于所在的作用域</p>
</li>
<li><p>全局上下文环境==&gt;全局作用域</p>
</li>
<li><p>函数上下文环境==&gt;对应的函数使用域</p>
</li>
</ul>
<h3 id="作用域链"><a href="#作用域链" class="headerlink" title="作用域链"></a>作用域链</h3><p>当在函数作用域操作一个变量时，它会先在自身作用域中寻找，如果有就直接使用（<strong>就近原则</strong>）。如果没有则向上一级作用域中寻找，直到找到全局作用域；如果全局作用域中依然没有找到，则会报错ReferenceError。</p>
<p>外部函数定义的变量可以被内部函数所使用，反之则不行。</p>
<pre><code class="hljs html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Title<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="actionscript">
        <span class="hljs-comment">//只要是函数就可以创造作用域</span>
        <span class="hljs-comment">//函数中又可以再创建函数</span>
        <span class="hljs-comment">//函数内部的作用域可以访问函数外部的作用域</span>
        <span class="hljs-comment">//如果有多个函数嵌套，那么就会构成一个链式访问结构，这就是作用域链</span>

        <span class="hljs-comment">//f1---&gt;全局</span>
        <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">f1</span><span class="hljs-params">()</span></span>&#123;
            <span class="hljs-comment">//f2---&gt;f1---&gt;全局</span>
            <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">f2</span><span class="hljs-params">()</span></span>&#123;
                <span class="hljs-comment">//f3----&gt;f2---&gt;f1---&gt;全局</span>
                <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">f3</span><span class="hljs-params">()</span></span>&#123;
                &#125;
                <span class="hljs-comment">//f4---&gt;f2---&gt;f1----&gt;全局</span>
                <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">f4</span><span class="hljs-params">()</span></span>&#123;
                &#125;
            &#125;
            <span class="hljs-comment">//f5---&gt;f1----&gt;全局</span>
            <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">f5</span><span class="hljs-params">()</span></span>&#123;
            &#125;
        &#125;

    </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span></code></pre>

<p>理解：</p>
<ul>
<li><p>多个上下级关系的作用域形成的链, 它的方向是从下向上的(从内到外)</p>
</li>
<li><p>查找变量时就是沿着作用域链来查找的</p>
</li>
</ul>
<p>查找一个变量的查找规则：</p>
<pre><code class="hljs javascript"><span class="hljs-keyword">var</span> a = <span class="hljs-number">1</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fn1</span>(<span class="hljs-params"></span>) </span>&#123;
  <span class="hljs-keyword">var</span> b = <span class="hljs-number">2</span>

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fn2</span>(<span class="hljs-params"></span>) </span>&#123;
    <span class="hljs-keyword">var</span> c = <span class="hljs-number">3</span>
    <span class="hljs-built_in">console</span>.log(c)
    <span class="hljs-built_in">console</span>.log(b)
    <span class="hljs-built_in">console</span>.log(a)
    <span class="hljs-built_in">console</span>.log(d)
  &#125;
  fn2()
&#125;
fn1()</code></pre>


<ul>
<li><p>在当前作用域下的执行上下文中查找对应的属性, 如果有直接返回, 否则进入2</p>
</li>
<li><p>在上一级作用域的执行上下文中查找对应的属性, 如果有直接返回, 否则进入3</p>
</li>
<li><p>再次执行2的相同操作, 直到全局作用域, 如果还找不到就抛出找不到的异常</p>
</li>
</ul>
<h2 id="闭包"><a href="#闭包" class="headerlink" title="闭包"></a>闭包</h2><p>闭包就是能够读取其他函数内部数据（变量/函数）的函数。</p>
<p>只有函数内部的子函数才能读取局部变量，因此可以把闭包简单理解成”定义在一个函数内部的函数”。</p>
<p>上面这两句话，是阮一峰的文章里的，你不一定能理解，来看下面的讲解和举例。</p>
<h3 id="如何产生闭包"><a href="#如何产生闭包" class="headerlink" title="如何产生闭包"></a>如何产生闭包</h3><p><strong>当一个嵌套的内部(子)函数引用了嵌套的外部(父)函数的变量或函数时, 就产生了闭包。</strong></p>
<h3 id="闭包到底是什么"><a href="#闭包到底是什么" class="headerlink" title="闭包到底是什么?"></a>闭包到底是什么?</h3><blockquote>
<p>使用chrome调试查看</p>
</blockquote>
<ul>
<li><p>理解一: 闭包是嵌套的内部函数(绝大部分人)</p>
</li>
<li><p>理解二: 包含被引用变量 or 函数的对象(极少数人)</p>
</li>
</ul>
<p>注意: 闭包存在于嵌套的内部函数中。</p>
<h3 id="产生闭包的条件"><a href="#产生闭包的条件" class="headerlink" title="产生闭包的条件"></a>产生闭包的条件</h3><ul>
<li><p>1.函数嵌套</p>
</li>
<li><p>2.内部函数引用了外部函数的数据(变量/函数)。</p>
</li>
</ul>
<p>来看看条件2：</p>
<pre><code class="hljs javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fn1</span>(<span class="hljs-params"></span>) </span>&#123;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fn2</span>(<span class="hljs-params"></span>) </span>&#123;

    &#125;

    <span class="hljs-keyword">return</span> fn2;
&#125;

fn1();</code></pre>

<p>上面的代码不会产生闭包，因为内部函数fn2并没有引用外部函数fn1的变量。</p>
<p>PS：还有一个条件是<strong>外部函数被调用，内部函数被声明</strong>。比如：</p>
<pre><code class="hljs javascript">
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fn1</span>(<span class="hljs-params"></span>) </span>&#123;
    <span class="hljs-keyword">var</span> a = <span class="hljs-number">2</span>
    <span class="hljs-keyword">var</span> b = <span class="hljs-string">'abc'</span>

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fn2</span>(<span class="hljs-params"></span>) </span>&#123; <span class="hljs-comment">//fn2内部函数被提前声明，就会产生闭包(不用调用内部函数)</span>
        <span class="hljs-built_in">console</span>.log(a)
    &#125;

&#125;

fn1();

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fn3</span>(<span class="hljs-params"></span>) </span>&#123;
    <span class="hljs-keyword">var</span> a = <span class="hljs-number">3</span>
    <span class="hljs-keyword">var</span> fun4 = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>&#123;  <span class="hljs-comment">//fun4采用的是“函数表达式”创建的函数，此时内部函数的声明并没有提前</span>
        <span class="hljs-built_in">console</span>.log(a)
    &#125;
&#125;

fn3();</code></pre>




<h2 id="常见的闭包"><a href="#常见的闭包" class="headerlink" title="常见的闭包"></a>常见的闭包</h2><ul>
<li><ol>
<li>将一个函数作为另一个函数的返回值</li>
</ol>
</li>
<li><ol start="2">
<li>将函数作为实参传递给另一个函数调用。</li>
</ol>
</li>
</ul>
<h3 id="闭包1：将一个函数作为另一个函数的返回值"><a href="#闭包1：将一个函数作为另一个函数的返回值" class="headerlink" title="闭包1：将一个函数作为另一个函数的返回值"></a>闭包1：将一个函数作为另一个函数的返回值</h3><pre><code class="hljs javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fn1</span>(<span class="hljs-params"></span>) </span>&#123;
  <span class="hljs-keyword">var</span> a = <span class="hljs-number">2</span>

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fn2</span>(<span class="hljs-params"></span>) </span>&#123;
    a++
    <span class="hljs-built_in">console</span>.log(a)
  &#125;
  <span class="hljs-keyword">return</span> fn2
&#125;

<span class="hljs-keyword">var</span> f = fn1();   <span class="hljs-comment">//执行外部函数fn1，返回的是内部函数fn2</span>
f() <span class="hljs-comment">// 3       //执行fn2</span>
f() <span class="hljs-comment">// 4       //再次执行fn2</span></code></pre>


<p>当f()第二次执行的时候，a加1了，也就说明了：闭包里的数据没有消失，而是保存在了内存中。如果没有闭包，代码执行完倒数第三行后，变量a就消失了。</p>
<p>上面的代码中，虽然调用了内部函数两次，但是，闭包对象只创建了一个。</p>
<p>也就是说，要看闭包对象创建了一个，就看：<strong>外部函数执行了几次</strong>（与内部函数执行几次无关）。</p>
<h3 id="闭包2-将函数作为实参传递给另一个函数调用"><a href="#闭包2-将函数作为实参传递给另一个函数调用" class="headerlink" title="闭包2. 将函数作为实参传递给另一个函数调用"></a>闭包2. 将函数作为实参传递给另一个函数调用</h3><pre><code class="hljs javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">showDelay</span>(<span class="hljs-params">msg, time</span>) </span>&#123;
  setTimeout(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>&#123;  <span class="hljs-comment">//这个function是闭包，因为是嵌套的子函数，而且引用了外部函数的变量msg</span>
    alert(msg)
  &#125;, time)
&#125;
showDelay(<span class="hljs-string">'atguigu'</span>, <span class="hljs-number">2000</span>)</code></pre>

<p>上面的代码中，闭包是里面的funciton，因为它是嵌套的子函数，而且引用了外部函数的变量msg。</p>
<h2 id="闭包的作用"><a href="#闭包的作用" class="headerlink" title="闭包的作用"></a>闭包的作用</h2><ul>
<li><p>作用1. 使用函数内部的变量在函数执行完后, 仍然存活在内存中(延长了局部变量的生命周期)</p>
</li>
<li><p>作用2. 让函数外部可以操作(读写)到函数内部的数据(变量/函数)</p>
</li>
</ul>
<p>我们让然拿这段代码来分析：</p>
<pre><code class="hljs javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fn1</span>(<span class="hljs-params"></span>) </span>&#123;
  <span class="hljs-keyword">var</span> a = <span class="hljs-number">2</span>

  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fn2</span>(<span class="hljs-params"></span>) </span>&#123;
    a++
    <span class="hljs-built_in">console</span>.log(a)
  &#125;
  <span class="hljs-keyword">return</span> fn2;
&#125;

<span class="hljs-keyword">var</span> f = fn1();   <span class="hljs-comment">//执行外部函数fn1，返回的是内部函数fn2</span>
f() <span class="hljs-comment">// 3       //执行fn2</span>
f() <span class="hljs-comment">// 4       //再次执行fn2</span></code></pre>

<p><strong>作用1分析</strong>：</p>
<p>上方代码中，外部函数fn1执行完毕后，变量a并没有立即消失，而是保存在内存当中。</p>
<p><strong>作用2分析：</strong></p>
<p>函数fn1中的变量a，是在fn1这个函数作用域内，因此外部无法访问。但是通过闭包，外部就可以操作到变量a。</p>
<p>达到的效果是：<strong>外界看不到变量a，但可以操作a</strong>。</p>
<p>比如上面达到的效果是：我看不到变量a，但是每次执行函数后，让a加1。当然，如果我真想看到a，我可以在fn2中将a返回即可。</p>
<p>回答几个问题：</p>
<ul>
<li>问题1. 函数执行完后, 函数内部声明的局部变量是否还存在?</li>
</ul>
<p>答案：一般是不存在, 存在于闭包中的变量才可能存在。</p>
<p>闭包能够一直存在的根本原因是<code>f</code>，因为<code>f</code>接收了<code>fn1()</code>，这个是闭包，闭包里有a。注意，此时，fn2并不存在了，但是里面的对象（即闭包）依然存在，因为用<code>f</code>接收了。</p>
<ul>
<li>问题2. 在函数外部能直接访问函数内部的局部变量吗?</li>
</ul>
<p>不能，但我们可以通过闭包让外部操作它。</p>
<h2 id="闭包的生命周期"><a href="#闭包的生命周期" class="headerlink" title="闭包的生命周期"></a>闭包的生命周期</h2><ol>
<li><p>产生: 嵌套内部函数fn2被声明时就产生了(不是在调用)</p>
</li>
<li><p>死亡: 嵌套的内部函数成为垃圾对象时。（比如f = null，就可以让f成为垃圾对象。意思是，此时f不再引用闭包这个对象了）</p>
</li>
</ol>
<h2 id="闭包的应用：定义具有特定功能的js模块"><a href="#闭包的应用：定义具有特定功能的js模块" class="headerlink" title="闭包的应用：定义具有特定功能的js模块"></a>闭包的应用：定义具有特定功能的js模块</h2><ul>
<li><p>将所有的数据和功能都封装在一个函数内部(私有的)，只向外暴露一个包含n个方法的对象或函数。</p>
</li>
<li><p>模块的使用者, 只需要通过模块暴露的对象调用方法来实现对应的功能。</p>
</li>
</ul>
<h3 id="方式一"><a href="#方式一" class="headerlink" title="方式一"></a>方式一</h3><p>（1）myModule.js：（定义一个模块，向外暴露多个函数，供外界调用）</p>
<pre><code class="hljs javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">myModule</span>(<span class="hljs-params"></span>) </span>&#123;
    <span class="hljs-comment">//私有数据</span>
    <span class="hljs-keyword">var</span> msg = <span class="hljs-string">'Smyhvae Haha'</span>

    <span class="hljs-comment">//操作私有数据的函数</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">doSomething</span>(<span class="hljs-params"></span>) </span>&#123;
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'doSomething() '</span> + msg.toUpperCase()); <span class="hljs-comment">//字符串大写</span>
    &#125;

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">doOtherthing</span>(<span class="hljs-params"></span>) </span>&#123;
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'doOtherthing() '</span> + msg.toLowerCase()) <span class="hljs-comment">//字符串小写</span>
    &#125;

    <span class="hljs-comment">//通过【对象字面量】的形式进行包裹，向外暴露多个函数</span>
    <span class="hljs-keyword">return</span> &#123;
        <span class="hljs-attr">doSomething1</span>: doSomething,
        <span class="hljs-attr">doOtherthing2</span>: doOtherthing
    &#125;
&#125;</code></pre>


<p>上方代码中，外界可以通过doSomething1和doOtherthing2来操作里面的数据，但不让外界看到。</p>
<p>（2）index.html:</p>
<pre><code class="hljs html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>05_闭包的应用_自定义JS模块<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-comment">&lt;!--
闭包的应用 : 定义JS模块
  * 具有特定功能的js文件
  * 将所有的数据和功能都封装在一个函数内部(私有的)
  * 【重要】只向外暴露一个包含n个方法的对象或函数
  * 模块的使用者, 只需要通过模块暴露的对象调用方法来实现对应的功能
--&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text/javascript"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"myModule.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text/javascript"</span>&gt;</span><span class="javascript">
    <span class="hljs-keyword">var</span> <span class="hljs-built_in">module</span> = myModule();
    <span class="hljs-built_in">module</span>.doSomething1();
    <span class="hljs-built_in">module</span>.doOtherthing2();
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span></code></pre>


<h3 id="方式二"><a href="#方式二" class="headerlink" title="方式二"></a>方式二</h3><p>同样是实现方式一种的功能，这里我们采取另外一种方式。</p>
<p>（1）myModule2.js：（是一个立即执行的匿名函数）</p>
<pre><code class="hljs javascript">(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>&#123;
    <span class="hljs-comment">//私有数据</span>
    <span class="hljs-keyword">var</span> msg = <span class="hljs-string">'Smyhvae Haha'</span>

    <span class="hljs-comment">//操作私有数据的函数</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">doSomething</span>(<span class="hljs-params"></span>) </span>&#123;
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'doSomething() '</span> + msg.toUpperCase())
    &#125;

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">doOtherthing</span>(<span class="hljs-params"></span>) </span>&#123;
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'doOtherthing() '</span> + msg.toLowerCase())
    &#125;

    <span class="hljs-comment">//外部函数是即使运行的匿名函数，我们可以把两个方法直接传给window对象</span>
    <span class="hljs-built_in">window</span>.myModule = &#123;
        <span class="hljs-attr">doSomething1</span>: doSomething,
        <span class="hljs-attr">doOtherthing2</span>: doOtherthing
    &#125;
&#125;)()</code></pre>


<p>（2）index.html：</p>
<pre><code class="hljs html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>05_闭包的应用_自定义JS模块2<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-comment">&lt;!--
闭包的应用2 : 定义JS模块
  * 具有特定功能的js文件
  * 将所有的数据和功能都封装在一个函数内部(私有的)
  * 只向外暴露一个包信n个方法的对象或函数
  * 模块的使用者, 只需要通过模块暴露的对象调用方法来实现对应的功能
--&gt;</span>

<span class="hljs-comment">&lt;!--引入myModule文件--&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text/javascript"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"myModule2.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text/javascript"</span>&gt;</span>
    myModule.doSomething1()
    myModule.doOtherthing2()
<span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span></code></pre>

<p>上方两个文件中，我们在<code>myModule2.js</code>里直接把两个方法直接传递给window对象了。于是，在index.html中引入这个js文件后，会立即执行里面的匿名函数。在index.html中把myModule直接拿来用即可。</p>
<p><strong>总结：</strong></p>
<p>当然，方式一和方式二对比后，我们更建议采用方式二，因为很方便。</p>
<p>但无论如何，两种方式都采用了闭包。</p>
<h2 id="闭包的缺点及解决"><a href="#闭包的缺点及解决" class="headerlink" title="闭包的缺点及解决"></a>闭包的缺点及解决</h2><p>缺点：函数执行完后, 函数内的局部变量没有释放，占用内存时间会变长，容易造成内存泄露。</p>
<p>解决：能不用闭包就不用，及时释放。比如：</p>
<pre><code class="hljs javascript">f = <span class="hljs-literal">null</span>;  <span class="hljs-comment">// 让内部函数成为垃圾对象 --&gt;回收闭包</span></code></pre>

<p>总而言之，你需要它，就是优点；你不需要它，就成了缺点。</p>
<h2 id="内存溢出和内存泄露"><a href="#内存溢出和内存泄露" class="headerlink" title="内存溢出和内存泄露"></a>内存溢出和内存泄露</h2><h3 id="内存溢出"><a href="#内存溢出" class="headerlink" title="内存溢出"></a>内存溢出</h3><p><strong>内存溢出</strong>：一种程序运行出现的错误。当程序运行<strong>需要的内存</strong>超过了剩余的内存时, 就出抛出内存溢出的错误。</p>
<p>代码举例：</p>
<pre><code class="hljs javascript"><span class="hljs-keyword">var</span> obj = &#123;&#125;;
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">10000</span>; i++) &#123;
obj[i] = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Array</span>(<span class="hljs-number">10000000</span>);  <span class="hljs-comment">//把所有的数组内容都放到obj里保存，导致obj占用了很大的内存空间</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">"-----"</span>);
&#125;</code></pre>

<h3 id="内存泄漏"><a href="#内存泄漏" class="headerlink" title="内存泄漏"></a>内存泄漏</h3><p><strong>内存泄漏</strong>：<strong>占用的内存</strong>没有及时释放。</p>
<p>注意，内存泄露的次数积累多了，就容易导致内存溢出。</p>
<p><strong>常见的内存泄露</strong>：</p>
<ul>
<li><p>1.意外的全局变量</p>
</li>
<li><p>2.没有及时清理的计时器或回调函数</p>
</li>
<li><p>3.闭包</p>
</li>
</ul>
<p>情况1举例：</p>
<pre><code class="hljs javascript"><span class="hljs-comment">// 意外的全局变量</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fn</span>(<span class="hljs-params"></span>) </span>&#123;
    a = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Array</span>(<span class="hljs-number">10000000</span>);
    <span class="hljs-built_in">console</span>.log(a);
&#125;

fn();</code></pre>

<p>情况2举例：</p>
<pre><code class="hljs javascript"><span class="hljs-comment">// 没有及时清理的计时器或回调函数</span>
<span class="hljs-keyword">var</span> intervalId = setInterval(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>&#123; <span class="hljs-comment">//启动循环定时器后不清理</span>
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'----'</span>)
&#125;, <span class="hljs-number">1000</span>)

<span class="hljs-comment">// clearInterval(intervalId);  //清理定时器</span></code></pre>

<p>情况3举例：</p>
<pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text/javascript"</span>&gt;</span><span class="javascript">
  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fn1</span>(<span class="hljs-params"></span>) </span>&#123;
    <span class="hljs-keyword">var</span> a = <span class="hljs-number">4</span>;
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fn2</span>(<span class="hljs-params"></span>) </span>&#123;
      <span class="hljs-built_in">console</span>.log(++a)
    &#125;
    <span class="hljs-keyword">return</span> fn2
  &#125;
  <span class="hljs-keyword">var</span> f = fn1()
  f()

  <span class="hljs-comment">// f = null //让内部函数成为垃圾对象--&gt;回收闭包</span>
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></code></pre>












            </article>
            <hr>
            <div>
              <div class="post-metas mb-3">
                
                
                  <div class="post-meta">
                    <i class="iconfont icon-tags"></i>
                    
                      <a class="hover-with-bg" href="/zezhang/tags/JavaScript/">JavaScript</a>
                    
                  </div>
                
              </div>
              
                <p class="note note-warning">本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-sa/4.0/deed.zh" target="_blank" rel="nofollow noopener noopener">CC BY-SA 4.0 协议</a> ，转载请注明出处！</p>
              
              
                <div class="post-prevnext row">
                  <div class="post-prev col-6">
                    
                    
                      <a href="/zezhang/2020/02/01/%E5%9E%82%E7%9B%B4%E5%B1%85%E4%B8%AD%E7%9A%84N%E7%A7%8D%E5%8A%9E%E6%B3%95/">
                        <i class="iconfont icon-arrowleft"></i>
                        <span class="hidden-mobile">垂直居中的N种办法</span>
                        <span class="visible-mobile">Previous</span>
                      </a>
                    
                  </div>
                  <div class="post-next col-6">
                    
                    
                  </div>
                </div>
              
            </div>

            
          </div>
        </div>
      </div>
    </div>
    
      <div class="d-none d-lg-block col-lg-2 toc-container" id="toc-ctn">
        <div id="toc">
  <p class="toc-header"><i class="iconfont icon-list"></i>&nbsp;TOC</p>
  <div id="tocbot"></div>
</div>

      </div>
    
  </div>
</div>

<!-- Custom -->


    
  </main>

  
    <a id="scroll-top-button" href="#" role="button">
      <i class="iconfont icon-arrowup" aria-hidden="true"></i>
    </a>
  

  
    <div class="modal fade" id="modalSearch" tabindex="-1" role="dialog" aria-labelledby="ModalLabel"
     aria-hidden="true">
  <div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
    <div class="modal-content">
      <div class="modal-header text-center">
        <h4 class="modal-title w-100 font-weight-bold">Search</h4>
        <button type="button" id="local-search-close" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body mx-3">
        <div class="md-form mb-5">
          <input type="text" id="local-search-input" class="form-control validate">
          <label data-error="x" data-success="v"
                 for="local-search-input">keyword</label>
        </div>
        <div class="list-group" id="local-search-result"></div>
      </div>
    </div>
  </div>
</div>
  

  

  

  <footer class="mt-5">
  <div class="text-center py-3">
    <div>
      <a href="https://hexo.io" target="_blank" rel="nofollow noopener"><span>Hexo</span></a>
      <i class="iconfont icon-love"></i>
      <a href="https://github.com/fluid-dev/hexo-theme-fluid" target="_blank" rel="nofollow noopener">
        <span>Fluid</span></a>
    </div>
    
  <div class="statistics">
    
    

    
      
        <!-- 不蒜子统计PV -->
        <span id="busuanzi_container_site_pv" style="display: none">
            总访问量 
            <span id="busuanzi_value_site_pv"></span>
             次
          </span>
      
      
        <!-- 不蒜子统计UV -->
        <span id="busuanzi_container_site_uv" style="display: none">
            总访客数 
            <span id="busuanzi_value_site_uv"></span>
             人
          </span>
      
    
  </div>


    

    
  </div>
</footer>

<!-- SCRIPTS -->
<script  src="https://cdn.staticfile.org/jquery/3.4.1/jquery.min.js" ></script>
<script  src="https://cdn.staticfile.org/twitter-bootstrap/4.4.1/js/bootstrap.min.js" ></script>
<script  src="/zezhang/js/debouncer.js" ></script>
<script  src="/zezhang/js/main.js" ></script>

<!-- Plugins -->


  
    <script  src="/zezhang/js/lazyload.js" ></script>
  



  <script defer src="https://cdn.staticfile.org/clipboard.js/2.0.6/clipboard.min.js" ></script>
  <script  src="/zezhang/js/clipboard-use.js" ></script>



  <script defer src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js" ></script>





  <script  src="https://cdn.staticfile.org/tocbot/4.11.1/tocbot.min.js" ></script>
  <script>
    $(document).ready(function () {
      var boardCtn = $('#board-ctn');
      var boardTop = boardCtn.offset().top;

      tocbot.init({
        tocSelector: '#tocbot',
        contentSelector: 'article.markdown-body',
        headingSelector: 'h1,h2,h3,h4,h5,h6',
        linkClass: 'tocbot-link',
        activeLinkClass: 'tocbot-active-link',
        listClass: 'tocbot-list',
        isCollapsedClass: 'tocbot-is-collapsed',
        collapsibleClass: 'tocbot-is-collapsible',
        collapseDepth: 0,
        scrollSmooth: true,
        headingsOffset: -boardTop
      });
      if ($('.toc-list-item').length > 0) {
        $('#toc').css('visibility', 'visible');
      }
    });
  </script>



  <script  src="https://cdn.staticfile.org/typed.js/2.0.11/typed.min.js" ></script>
  <script>
    var typed = new Typed('#subtitle', {
      strings: [
        '  ',
        "作用域和封包&nbsp;",
      ],
      cursorChar: "_",
      typeSpeed: 70,
      loop: false,
    });
    typed.stop();
    $(document).ready(function () {
      $(".typed-cursor").addClass("h2");
      typed.start();
    });
  </script>



  <script  src="https://cdn.staticfile.org/anchor-js/4.2.2/anchor.min.js" ></script>
  <script>
    anchors.options = {
      placement: "right",
      visible: "hover",
      
    };
    var el = "h1,h2,h3,h4,h5,h6".split(",");
    var res = [];
    for (item of el) {
      res.push(".markdown-body > " + item)
    }
    anchors.add(res.join(", "))
  </script>



  <script  src="/zezhang/js/local-search.js" ></script>
  <script>
    var path = "/zezhang/local-search.xml";
    var inputArea = document.querySelector("#local-search-input");
    inputArea.onclick = function () {
      searchFunc(path, 'local-search-input', 'local-search-result');
      this.onclick = null
    }
  </script>



  <script  src="https://cdn.staticfile.org/fancybox/3.5.7/jquery.fancybox.min.js" ></script>
  <link  rel="stylesheet" href="https://cdn.staticfile.org/fancybox/3.5.7/jquery.fancybox.min.css" />

  <script>
    $('#post img:not(.no-zoom img, img[no-zoom]), img[zoom]').each(
      function () {
        var element = document.createElement('a');
        $(element).attr('data-fancybox', 'images');
        $(element).attr('href', $(this).attr('src'));
        $(this).wrap(element);
      }
    );
  </script>




















</body>
</html>
